
#include <FastLED.h>
#include <Arduino.h>

#define LED_PIN    5   //灯带信号--NODEMCU D1
#define MIC_PIN    A0  //MAX9814 OUT引脚
#define NUMPIXELS 32
//灯数
#define delay_time 20      //闪灯间隔
#define SEG_4_NUM   4

#define COLOR_ORDER GRB    // 色序
#define LED_TYPE WS2812    // LED灯带型号

CRGB leds[NUMPIXELS];            // 建立光带leds

unsigned long drop_time;//触发掉落时机

int sig_max = 1024;   //初始最大值

int si;
int pre_si;

int g_color = 250;              //起始颜色
int maxBrightness = 250;      //最大亮度
int effects = 0;              //默认灯效
int brightness_delta = int(maxBrightness / NUMPIXELS);
int color_delta = int(g_color / NUMPIXELS);  

int start_dot = NUMPIXELS/2-3;

int sig = 0;            /* 每隔一段时间的采样值 */
int last_sig = 0;       /* 上个时间的采样值 */


//以下是2.0的变量
int g_trigger_level = 700;    /* 麦克风音量触发值，麦克风采样范围0-1024，400为音量中间值，类似环境噪声 */
int sig_bigger = 0;     /* 是不是采样到了更大的音量变化 */
int noise_level = 100;   /* 噪声阈值，MAX8914 噪声在采样值400上下浮动， 450认为需要亮灯了，差值50，扩大，会提高扛噪声能力 */
int max_noise_level = 300;   /* 噪声阈值，MAX8914 噪声在采样值400上下浮动， 450认为需要亮灯了，差值50，扩大，会提高扛噪声能力 */
int sig_delta  = 0;       /* 音量变化的绝对值，越大表示音量变的越大 */
int pre_sig_delta  = 0;   /* 上一次音量变化的绝对值 */
int per_dot_drop_time = 15;//多少ms，每个灯掉落的时间延迟，影响视觉效果
int stop_sample = 0;  /* 是否暂停采样 */
int pre_dot = 0;  //上次最高点
int dot = 0;      //本次最高点
int last_si = 0;  //上次音量值
int drop_dot_color = 130;     //掉落点颜色
int drop_dot_brightness = 250;//掉落点亮度
long last_drop_time = 0;      //上次掉落点掉落的时间

int seg_dot =0; //段落起点
int pre_seg_dot =0; //上次段落起点

void set_sig(int si){

  if(stop_sample) return;

#if 1
  //Serial.printf("read si = %d\r\n",si);
  //Serial.println(si);
  if(si > g_trigger_level)
    sig_delta = si - g_trigger_level;
  else if(si<100)
    sig_delta = 400 - si;
  else sig_delta = 0;
  //Serial.printf("set sig_delta = %d\r\n",sig_delta);
#else
  /* 相邻两次差值较大，说明音量变化大 */
  if(si > last_si)
    sig_delta = si - last_si;
  else if(si < last_si)
    sig_delta = last_si - si;
#endif  
 
  if(sig_delta> noise_level){
    //Serial.printf("sig_delta display = %d\r\n",sig_delta);

    //这个音量应该要显示出来
    //{
      if(sig_delta > max_noise_level)//防止超范围崩溃
        sig_delta = max_noise_level;
        
      dot = map(sig_delta,noise_level,max_noise_level, 0, NUMPIXELS-2);//最高点留给掉落点,最大值30
      dot = constrain(dot, 0, NUMPIXELS-2); //防止映射值超出范围
      if(dot < 1){
        //Serial.printf("sig_delta display = %d\r\n",sig_delta);
        dot = 0;
        //Serial.printf("dot===========%d\r\n",dot);  
      }  
      
      if(pre_sig_delta > sig_delta)// 比上次的音量更大
      {
        sig_bigger = 1;      
      }      
      else  //比上次小的音量，不影响灯继续掉落
        sig_bigger = 0;
        
    pre_sig_delta = sig_delta;
  }
  last_si = si;
  return;
}

int set_brightness(int brightness){
  Serial.printf("maxBrightness = %d\n",maxBrightness);
  maxBrightness = brightness;
  brightness_delta = maxBrightness / NUMPIXELS;
  return 0;  
}

int get_brightness(){
  Serial.printf("maxBrightness = %d\n",maxBrightness);
  return maxBrightness;
}

int get_trigger_level(){
  Serial.printf("g_trigger_level = %d\n",g_trigger_level);
  return g_trigger_level;
}

int set_trigger_level(int level){
  Serial.printf("g_trigger_level = %d\n",g_trigger_level);
  g_trigger_level = level;
  return 0;  
}

int set_color(int color){
  Serial.printf("g_color = %d\n",g_color);
  g_color = color;
  color_delta = int(g_color / NUMPIXELS);
  return 0;
}

int get_color(){
  Serial.printf("g_color = %d\n",g_color);
  return g_color;
}

int get_effects(){
  //Serial.printf("effects = %d\n",effects);
  return effects;  
}

int set_effects( int effect){
  Serial.printf("effects = %d\n",effects);
  effects = effect;
  return 0;
}

void led_test(){
  #if 0
  fill_rainbow(leds, 32, 0, 5);
  FastLED.show();
  delay(1000);
  FastLED.clear(); 
  #endif  

#if 1  
  int i;
  for(i = 0; i< NUMPIXELS; i++)
  {
     //fill_solid(leds + i, 1, CHSV((g_color+i * color_delta)%255, 255, 250));
     leds[i] = CHSV(133, 255, 250);
     FastLED.show();
     delay(20);
  }
  //FastLED.show();
  delay(1000);
  FastLED.clear(); 
#endif 

}

//上升，逐次点亮
void  led_init(){
  // LED init
  LEDS.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUMPIXELS);
  FastLED.setBrightness(maxBrightness);  
  led_test();
}

int drop_dot = 0;
int drop_dot2 = 1;
int pre_drop_dot = 0;

void clear_led(){

  drop_dot = 0;
  dot = 0;
  pre_dot = 0;
  pre_sig_delta = 0;
  last_drop_time = 0;

  pre_drop_dot = 0;
  drop_dot2 = 1;
  pre_si = 0;
  
  FastLED.clear();
  FastLED.show();
}


/*
音效描述：
1）HUE 色，上推+掉落效果，0掉落点
*/
void music_0_drop(){
  
  if(pre_dot < dot){//音量更大，需要迅速提升到指定高度        

      int i = pre_dot;
      for(i = pre_dot; i<= dot; i++)
      {
         fill_solid(leds + i, 1, CHSV((g_color+i * color_delta)%255, 255, 30 * brightness_delta));
      }
      FastLED.show();
      pre_dot = dot;//记录此次停留的最高点，后面就开始掉落
      //delay(per_dot_drop_time);
      
      //恢复采样
      //stop_sample = 0;
      
  }
  //Serial.printf("pre_dot=%d\r\n",pre_dot);
  
  // 慢慢掉落，要从上次掉落的地方继续掉落，一直掉落到全部灭掉，或者来了更强的声音
  int j = pre_dot;
  for(j = pre_dot; j>=0; j--){
      //Serial.printf("pre_dot j=%d\r\n",j);
      fill_solid(leds + j, 1, CHSV(0, 255, 0));
      FastLED.show();
      
      for(int t=0; t< per_dot_drop_time; t++){//把掉落时间打散
         if(sig_bigger){ //如果有更大音量，立刻退出，记录此次停留的最高点
         //if(0){ //如果有更大音量，立刻退出，记录此次停留的最高点          
            //停止继续采样，把这次更高音量的逻辑处理完才可以继续采样
            //stop_sample = 1;
            sig_bigger = 0;// 放置下次循环到这里，又直接退出了
            pre_dot = j;
            //Serial.printf("sig_bigger break pre_dot=%d\r\n",j);
            return;            
         }
         delay(1);  
      }      
  }
  pre_dot = 0;
  return;  
}

/*
音效描述：
1）HUE 色，上推+掉落效果，1个掉落点，快速掉落，可以发掘下其他效果
*/
void music_1_drop_fast(){
  
  if(pre_dot < dot){//音量更大，需要迅速提升到指定高度        

      int i = pre_dot;
      for(i = pre_dot; i<= dot; i++)
      {
         fill_solid(leds + i, 1, CHSV((g_color+i * color_delta)%255, 255, 30 * brightness_delta));
      }
      FastLED.show();
      pre_dot = dot;//记录此次停留的最高点，后面就开始掉落
      //delay(per_dot_drop_time);

      //关掉上次掉落点
      fill_solid(leds + pre_drop_dot, 1, CHSV(0,0,0));

      //产生新的掉落点
      if(dot == NUMPIXELS - 2)
        drop_dot = dot +1;  
      else
        drop_dot = dot +2;
        
      fill_solid(leds + drop_dot, 1, CHSV(drop_dot_color, 255, drop_dot_brightness));
      FastLED.show();
  }

  //Serial.printf("pre_dot=%d\r\n",pre_dot);
  
  // 慢慢掉落，要从上次掉落的地方继续掉落，一直掉落到全部灭掉，或者来了更强的声音
  int j = pre_dot;
  for(j = pre_dot; j>=0; j--){
      //Serial.printf("pre_dot j=%d\r\n",j);
      fill_solid(leds + j, 1, CHSV(0, 255, 0));
      
      if(drop_dot > 0)
        fill_solid(leds+drop_dot--, 1, CHSV(0, 255, 0));
      
      fill_solid(leds+drop_dot, 1, CHSV(drop_dot_color, 255, drop_dot_brightness));
      FastLED.show();
      pre_drop_dot = drop_dot;
      
      for(int t=0; t< per_dot_drop_time; t++){//把掉落时间打散
         if(sig_bigger){ //如果有更大音量，立刻退出，记录此次停留的最高点
         //if(0){ //如果有更大音量，立刻退出，记录此次停留的最高点          
            sig_bigger = 0;// 放置下次循环到这里，又直接退出了
            pre_dot = j;
            //Serial.printf("sig_bigger break pre_dot=%d\r\n",j);
            return;            
         }
         delay(1);  
      }      
  }
  pre_dot = 0;
  return;  
}

/*
音效描述：
1）HUE 色，上推+掉落效果，1个掉落点，慢速掉落，音量增大会重新生成新的掉落点
*/
void music_1_drop_slow(){
  
  if(pre_dot < dot){//音量更大，需要迅速提升到指定高度        

      //先关掉上次掉落点
      fill_solid(leds + drop_dot, 1, CHSV(0,0,0));
      
      int i = pre_dot;
      for(i = pre_dot; i<= dot; i++)
      {
         fill_solid(leds + i, 1, CHSV((g_color+i * color_delta)%255, 255, 30 * brightness_delta));
      }
      FastLED.show();
      pre_dot = dot;//记录此次停留的最高点，后面就开始掉落
      //delay(per_dot_drop_time);

      //产生新的掉落点
      if(dot == NUMPIXELS - 2)
        drop_dot = dot +1;  
      else
        drop_dot = dot +2;
        
      fill_solid(leds + drop_dot, 1, CHSV(drop_dot_color, 255, drop_dot_brightness));
      FastLED.show();
  }

  //Serial.printf("pre_dot=%d\r\n",pre_dot);

  if(millis() - last_drop_time > 200 ){
    if(drop_dot > 0)
      fill_solid(leds+drop_dot--, 1, CHSV(0, 255, 0));
    
    fill_solid(leds+drop_dot, 1, CHSV(drop_dot_color, 255, drop_dot_brightness));
    FastLED.show();
    
    last_drop_time = millis();
  } 
  // 慢慢掉落，要从上次掉落的地方继续掉落，一直掉落到全部灭掉，或者来了更强的声音
  int j = pre_dot;
  for(j = pre_dot; j>0; j--){
      //Serial.printf("pre_dot j=%d\r\n",j);
      fill_solid(leds + j, 1, CHSV(0, 255, 0)); 
      FastLED.show();
      for(int t=0; t< per_dot_drop_time; t++){//把掉落时间打散
         if(sig_bigger){ //如果有更大音量，立刻退出，记录此次停留的最高点
         //if(0){ //如果有更大音量，立刻退出，记录此次停留的最高点          
            sig_bigger = 0;// 放置下次循环到这里，又直接退出了
            pre_dot = j-1;//准确计算当前位置
            //Serial.printf("sig_bigger break pre_dot=%d\r\n",j);
            return;            
         }
         delay(1);  
      }      
  }
  
  pre_dot = 0;
  return;  
}

/*
音效描述：
1）HUE 色，上推+掉落效果，1个掉落点，慢速掉落，音量增大会把上次掉落点推高
*/
void music_1_drop(){
  //Serial.printf("music_1_drop pre_dot=%d\r\n",pre_dot);
  if(pre_dot < dot){//音量更大，需要迅速提升到指定高度        

      if(dot >= drop_dot)// 只有掉落到音量最高点，才重新设置掉落点
      {      
        
        //掉落点推高
        if(dot == NUMPIXELS - 2)
          drop_dot = dot +1;  
        else
          drop_dot = dot +2;
      }     
        
      fill_solid(leds + drop_dot, 1, CHSV(drop_dot_color, 255, drop_dot_brightness));
      FastLED.show();
      
      int i = pre_dot;
      for(i = pre_dot; i<= dot; i++)
      {
         fill_solid(leds + i, 1, CHSV((g_color+i * color_delta)%255, 255, 30 * brightness_delta));
      }
      FastLED.show();
      pre_dot = dot;//记录此次停留的最高点，后面就开始掉落
      delay(per_dot_drop_time); 
  }

  //Serial.printf("pre_dot=%d\r\n",pre_dot);

  if(millis() - last_drop_time > 30 ){
    
    Serial.printf("drop_dot =%d\r\n",drop_dot);
    if(drop_dot > 0){
      fill_solid(leds+drop_dot--, 1, CHSV(0, 255, 0));//先关掉上次的掉落位置
    }       
    
    fill_solid(leds+drop_dot, 1, CHSV(drop_dot_color, 255, drop_dot_brightness));//点亮本次掉落位置
    
    FastLED.show();
    last_drop_time = millis();
  } 

  // 慢慢掉落，要从上次掉落的地方继续掉落，一直掉落到全部灭掉，或者来了更强的声音
  int j = pre_dot;
  for(j = pre_dot; j>0; j--){
      //Serial.printf("pre_dot j=%d\r\n",j);
      fill_solid(leds + j, 1, CHSV(0, 255, 0)); 
      FastLED.show();
      for(int t=0; t< per_dot_drop_time; t++){//把掉落时间打散
         if(sig_bigger){ //如果有更大音量，立刻退出，记录此次停留的最高点
         //if(0){ //如果有更大音量，立刻退出，记录此次停留的最高点          
            sig_bigger = 0;// 放置下次循环到这里，又直接退出了
            pre_dot = j-1;
            //Serial.printf("sig_bigger break pre_dot=%d\r\n",j);
            return;            
         }
         delay(1);  
      }      
  }
  
  pre_dot = 0;
  return;  
}

/*
音效描述：
1）HUE 色, 2 个掉落效果点
*/
void music_2_drop(){

  //Serial.printf("music_1_drop pre_dot=%d\r\n",pre_dot);
  if(pre_dot < dot){//音量更大，需要迅速提升到指定高度        

      if(dot >= drop_dot)// 只有掉落到音量最高点，才重新设置掉落点
      {      
        
        //掉落点推高
        if(dot == NUMPIXELS - 2)
          drop_dot = dot +1;  
        else
          drop_dot = dot +2;

        drop_dot2 = drop_dot+1;
      }     
        
      fill_solid(leds + drop_dot, 1, CHSV(drop_dot_color, 255, drop_dot_brightness));
      fill_solid(leds + drop_dot2, 1, CHSV(drop_dot_color, 255, drop_dot_brightness));
      FastLED.show();
      
      int i = pre_dot;
      for(i = pre_dot; i<= dot; i++)
      {
         fill_solid(leds + i, 1, CHSV((g_color+i * color_delta)%255, 255, 30 * brightness_delta));
      }
      FastLED.show();
      pre_dot = dot;//记录此次停留的最高点，后面就开始掉落
      delay(per_dot_drop_time); 
  }

  //Serial.printf("pre_dot=%d\r\n",pre_dot);

  if(millis() - last_drop_time > 30 ){
    
    Serial.printf("drop_dot =%d\r\n",drop_dot);
    if(drop_dot > 0){
      fill_solid(leds+drop_dot--, 1, CHSV(0, 255, 0));//先关掉上次的掉落位置
      fill_solid(leds+drop_dot2--, 1, CHSV(0, 255, 0));//先关掉上次的掉落位置      
    }       
    
    fill_solid(leds+drop_dot, 1, CHSV(drop_dot_color, 255, drop_dot_brightness));//点亮本次掉落位置
    fill_solid(leds+drop_dot2, 1, CHSV(drop_dot_color, 255, drop_dot_brightness));//点亮本次掉落位置
    
    FastLED.show();
    last_drop_time = millis();
  } 

  // 慢慢掉落，要从上次掉落的地方继续掉落，一直掉落到全部灭掉，或者来了更强的声音
  int j = pre_dot;
  for(j = pre_dot; j>0; j--){
      //Serial.printf("pre_dot j=%d\r\n",j);
      fill_solid(leds + j, 1, CHSV(0, 255, 0)); 
      FastLED.show();
      for(int t=0; t< per_dot_drop_time; t++){//把掉落时间打散
         if(sig_bigger){ //如果有更大音量，立刻退出，记录此次停留的最高点
         //if(0){ //如果有更大音量，立刻退出，记录此次停留的最高点          
            sig_bigger = 0;// 放置下次循环到这里，又直接退出了
            pre_dot = j-1;
            //Serial.printf("sig_bigger break pre_dot=%d\r\n",j);
            return;            
         }
         delay(1);  
      }      
  }
  
  pre_dot = 0;
  return;  
      
}


/*
音效描述：
1）HUE 色，气泡模式，气泡上升亮度和颜色渐变
*/
void music_pop(){
  int SEG_NUM = 10;
  int brightness_delta = maxBrightness/SEG_NUM;
  int color_delta = g_color /SEG_NUM;
  int sig = analogRead(MIC_PIN);//out引脚
  int start_dot = 0;
  //int delta = int(250 / NUMPIXELS);
  //int delta = int(120 / NUMPIXELS);
  int delta = random(0,250)/NUMPIXELS;//随机下颜色
  Serial.println(sig);
  
  if (sig >= g_trigger_level+50)
  //while(1)
  { 
    //Serial.println(sig);
    //int si = map(sig, triger_level, sig_max, 0, NUMPIXELS);
    for(int j = 0; j < NUMPIXELS; j++){
        for(int i = 0; i < SEG_NUM; i++){
            start_dot = j+i;
            int tmp_dot = start_dot%NUMPIXELS;// NUMPIXELS 为模，获取偏移位置
            if( tmp_dot >= SEG_NUM)
            {
              fill_solid(leds+tmp_dot-SEG_NUM, 1, CHSV(0, 255, 0));
            }
            
            fill_solid(leds+tmp_dot, 1, CHSV((g_color+i * color_delta)%255, 255, i * brightness_delta));
        }
        FastLED.show();
        delay(10);
    }
  }
}

/*
音效描述：
1）HUE 色，4点段落式 跳跃模式
*/
void music_seg_drop(){
  
  seg_dot = map(dot,0,NUMPIXELS-1, 0, NUMPIXELS/SEG_4_NUM - 1);//0-7 步
  //如果音量变大，就要把段从当前位置上移
  if(pre_seg_dot < seg_dot){
    
    //Serial.printf("seg_dot %d\n",seg_dot);
    Serial.printf("sig_delta %d, noise_level %d, max_noise_level %d,seg_dot %d\n",sig_delta, noise_level, max_noise_level,seg_dot);
    //移动新的位置
    {
      int i = pre_seg_dot;
      for(i = pre_seg_dot; i <= seg_dot; i++){
        for(int x = 0; x < SEG_4_NUM; x++){     
            fill_solid(leds+(i*SEG_4_NUM+x)%NUMPIXELS, 1, CHSV(g_color, 255, maxBrightness));
        }    
        FastLED.show();
      }
       
      pre_seg_dot = seg_dot;
      Serial.printf("seg_dot %d\n",seg_dot);
    }
    //delay(per_dot_drop_time);
    //pre_dot = dot;
  }
  
  if(millis() - last_drop_time > 200)  
  {
    //其他情况 段下降
 
    int i = pre_seg_dot; 
    for(i = pre_seg_dot; i>= seg_dot; i--){
      for(int x = 0; x < SEG_4_NUM; x++){
          fill_solid(leds+(i*SEG_4_NUM+x)%NUMPIXELS, 1, CHSV(0, 0, 0));
      }    
      FastLED.show();
      delay(30);
    }
    last_drop_time = millis();
    
    pre_seg_dot = seg_dot;
  }
  
  return;
}


/*
音效描述：
1）HUE 色，4点跳跃模式
*/
void music_dot_dance(){

  int SEG_NUM = 8;
  int brightness_delta = maxBrightness/SEG_4_NUM;
  int color_delta = g_color /SEG_NUM;
  int sig = analogRead(MIC_PIN);//out引脚

  int delta = random(0,250)/NUMPIXELS;//随机下颜色
  //Serial.println(sig);
  int trigger = g_trigger_level/5;//灵敏度
  if (sig >= 400 && sig - 400 > trigger ){
    si = sig - 400;
    Serial.printf("up %d\n",sig - 400);
  }else if(sig <= 400 && 400 - sig > trigger){
    si = 400 - sig;
    Serial.printf("down %d\n",400 - sig);
  }else{
    si = 0;  
  }

  if(si > trigger){
    
    if(si > pre_si){// 声音增大
  
      int move_step = map(si, 0, 200, 0, SEG_4_NUM);//15 步
      Serial.printf("move_step %d\n",move_step);      
      
      for(int y = 0; y < move_step; y++){
          // 关掉上次开始位置 要移动的几个点
         fill_solid(leds+(start_dot+y)%NUMPIXELS, 1, CHSV(0, 255, 0));         
      }
      FastLED.show();
      delay(50);
      if(start_dot+move_step <= NUMPIXELS-SEG_4_NUM){
        start_dot += move_step;
      
        for(int x = 0; x < SEG_4_NUM; x++){     
            //fill_solid(leds+(start_dot+x)%NUMPIXELS, 1, CHSV((g_color+x * color_delta)%255, 255, x * brightness_delta));
            fill_solid(leds+(start_dot+x)%NUMPIXELS, 1, CHSV(g_color, 255, maxBrightness));
        }
        FastLED.show();
        delay(50);
    
        start_dot = start_dot % NUMPIXELS;
        Serial.printf("start_dot %d\n",start_dot);
      }    
      
      pre_si = si;
    }else{  //声音变小
      int move_step = map(si, 0, 200, 0, SEG_4_NUM);//15 步
         for(int y = 0; y < move_step; y++){
          // 关掉要移动的几个点
         fill_solid(leds+(start_dot+SEG_4_NUM-y)%NUMPIXELS, 1, CHSV(0, 255, 0));
      }    
      FastLED.show();
      delay(50);
      
      if(start_dot - move_step >=0){
        start_dot -= move_step;
      
          for(int x = 0; x < SEG_4_NUM; x++){     
              //fill_solid(leds+(start_dot+x)%NUMPIXELS, 1, CHSV((g_color+x * color_delta)%255, 255, (SEG_4_NUM-x) * brightness_delta));
              fill_solid(leds+(start_dot+x)%NUMPIXELS, 1, CHSV(g_color, 255, maxBrightness));
          }
          FastLED.show();
          delay(50); 
          start_dot = start_dot % NUMPIXELS;     
     }     
            
      Serial.printf("start_dot %d\n",start_dot);
      pre_si = si;
    }
      
  } 
 
}


/*
音效描述：
1）HUE 色，段落跳跃模式
*/
void music_dance(){

  int SEG_NUM = 8;
  int brightness_delta = maxBrightness/SEG_NUM;
  int color_delta = g_color /SEG_NUM;
  int sig = analogRead(MIC_PIN);//out引脚

  int delta = random(0,250)/NUMPIXELS;//随机下颜色
  //Serial.println(sig);
  int trigger = 50;
  if (sig >= 400 && sig - 400 > trigger ){
    si = sig - 400;
    Serial.printf("up %d\n",sig - 400);
  }else if(sig <= 400 && 400 - sig > trigger){
    si = 400 - sig;
    Serial.printf("down %d\n",400 - sig);
  }else{
    si = 0;  
  }

  if(si > trigger){
    
    if(si > pre_si){// 声音增大
  
      int move_step = map(si, 0, 200, 0, SEG_NUM);//15 步
      Serial.printf("move_step %d\n",move_step);      
      
      for(int y = 0; y < move_step; y++){
          // 关掉上次开始位置 要移动的几个点
         fill_solid(leds+(start_dot+y)%NUMPIXELS, 1, CHSV(0, 255, 0));
      }
      FastLED.show();
      delay(50);
      if(start_dot+move_step <= NUMPIXELS-SEG_NUM){
        start_dot += move_step;
      
        for(int x = 0; x < SEG_NUM; x++){     
            fill_solid(leds+(start_dot+x)%NUMPIXELS, 1, CHSV((g_color+x * color_delta)%255, 255, x * brightness_delta));
        }
        FastLED.show();
        delay(50);
    
        start_dot = start_dot % NUMPIXELS;
        Serial.printf("start_dot %d\n",start_dot);
      }    
      
      pre_si = si;
    }else{  //声音变小
      int move_step = map(si, 0, 200, 0, SEG_NUM);//15 步
         for(int y = 0; y < move_step; y++){
          // 关掉要移动的几个点
         fill_solid(leds+(start_dot+SEG_NUM-y)%NUMPIXELS, 1, CHSV(0, 255, 0));

      }    
      FastLED.show();
      delay(50);
      
      if(start_dot - move_step >=0){
        start_dot -= move_step;
      
          for(int x = 0; x < SEG_NUM; x++){     
              fill_solid(leds+(start_dot+x)%NUMPIXELS, 1, CHSV((g_color+x * color_delta)%255, 255, x * brightness_delta));
          }
          FastLED.show();
          delay(50); 
          start_dot = start_dot % NUMPIXELS;     
     }
      Serial.printf("start_dot %d\n",start_dot);
      pre_si = si;
    }
      
  } 
 
}
/*
音效描述：
1）HUE 色，段落跳跃模式，单色模式
*/
void music_dance_single_color(){

  int SEG_NUM = 8;
  int brightness_delta = maxBrightness/SEG_NUM;
  int color_delta = g_color /SEG_NUM;
  int sig = analogRead(MIC_PIN);//out引脚

  int delta = random(0,250)/NUMPIXELS;//随机下颜色
  //Serial.println(sig);
  int trigger = 50;
  if (sig >= 400 && sig - 400 > trigger ){
    si = sig - 400;
    Serial.printf("up %d\n",sig - 400);
  }else if(sig <= 400 && 400 - sig > trigger){
    si = 400 - sig;
    Serial.printf("down %d\n",400 - sig);
  }else{
    si = 0;  
  }

  if(si > trigger){
    
    if(si > pre_si){// 声音增大
  
      int move_step = map(si, 0, 200, 0, SEG_NUM);//15 步
      Serial.printf("move_step %d\n",move_step);      
      
      for(int y = 0; y < move_step; y++){
          // 关掉上次开始位置 要移动的几个点
         fill_solid(leds+(start_dot+y)%NUMPIXELS, 1, CHSV(0, 255, 0));
         
      }
      FastLED.show();
      delay(30);
      if(start_dot+move_step <= NUMPIXELS-SEG_NUM){
        start_dot += move_step;
      
        for(int x = 0; x < SEG_NUM; x++){     
            fill_solid(leds+(start_dot+x)%NUMPIXELS, 1, CHSV(g_color, 255, x * brightness_delta));
        }
        FastLED.show();
        delay(30);
    
        start_dot = start_dot % NUMPIXELS;
        Serial.printf("start_dot %d\n",start_dot);
      }    
      
      pre_si = si;
    }else{  //声音变小
      int move_step = map(si, 0, 200, 0, SEG_NUM);//15 步
         for(int y = 0; y < move_step; y++){
          // 关掉上次开始位置 要移动的几个点
         fill_solid(leds+(start_dot+SEG_NUM-y)%NUMPIXELS, 1, CHSV(0, 255, 0));
      }    
      FastLED.show();
      delay(30);
      
      if(start_dot - move_step >=0){
        start_dot -= move_step;
      
          for(int x = 0; x < SEG_NUM; x++){     
              fill_solid(leds+(start_dot+x)%NUMPIXELS, 1, CHSV(g_color, 255, x * brightness_delta));
          }
          FastLED.show();
          delay(30); 
          start_dot = start_dot % NUMPIXELS;
     }     
            
      Serial.printf("start_dot %d\n",start_dot);
      pre_si = si;
    }
      
  } 
 
}

/*
音效描述：
1）HUE 色，由中心向外渐变扩展模式
*/

void music_extend_fade(){
  
  int delta = int(g_color / NUMPIXELS);

    //Serial.println(sig);
    int si = map(dot, 0, NUMPIXELS -1, 0, NUMPIXELS/2 - 1);
    Serial.printf("si222 %d\n", si); 
    if(si > pre_si){//音量更大 
      int m = si;
      for(int j = NUMPIXELS/2-1; m >= 0 && j >=0; j--, m--){
          Serial.printf("si %d\n", j); 
          if(j == 0){
            fill_solid(leds + j, 1, CHSV(delta%255, 255, brightness_delta)); 
            fill_solid(leds + NUMPIXELS-1 - j, 1, CHSV(delta%255, 255, brightness_delta));//17 18
          }
          else{
            fill_solid(leds + j, 1, CHSV((g_color+j * delta)%255, 255, j*2 * brightness_delta));//16 15 14 13
            fill_solid(leds + NUMPIXELS-1 - j, 1, CHSV((g_color+j * delta)%255, 255, j* 2 * brightness_delta));//17 18
          }
      }
      FastLED.show();          
      //delay(10);
      pre_si = si;  
      last_drop_time = millis();
    }
    //else
    {// 不管音量变不变，都继续掉落
#if 1      
      for(int j = NUMPIXELS/2-1 - pre_si; j < NUMPIXELS/2 -1 -si; j++){
        
        fill_solid(leds + j, 1, CHSV(j * delta, 255, 0));
        fill_solid(leds + NUMPIXELS-1 - j, 1, CHSV(j * delta, 255, 0));
		FastLED.show();
		delay(15);
	  }
      
#endif      
      pre_si = si; 
      last_drop_time = millis();
    }   
  //delay(5);       
}

/*
音效描述：
1）HUE 色，由中心向外扩展模式, 亮度恒定
*/

void music_extend(){
  
  int delta = int(g_color / NUMPIXELS);

    //Serial.println(sig);
    int si = map(dot, 0, NUMPIXELS -1, 0, NUMPIXELS/2 - 1);
    Serial.printf("si222 %d\n", si); 
    if(si > pre_si){//音量更大 
      int m = si;
      for(int j = NUMPIXELS/2-1; m >= 0 && j >=0; j--, m--){
          Serial.printf("si %d\n", j); 
          if(j == 0){
            fill_solid(leds + j, 1, CHSV(delta%255, 255, maxBrightness)); 
            fill_solid(leds + NUMPIXELS-1 - j, 1, CHSV(delta%255, 255, maxBrightness));//17 18
          }
          else{
            fill_solid(leds + j, 1, CHSV((g_color+j * delta)%255, 255, maxBrightness));//16 15 14 13
            fill_solid(leds + NUMPIXELS-1 - j, 1, CHSV((g_color+j * delta)%255, 255, maxBrightness));//17 18
          }
      }
      FastLED.show();          
      //delay(10);
      pre_si = si;  
      last_drop_time = millis();
    }
    //else
    {// 不管音量变不变，都继续掉落
#if 1      
      for(int j = NUMPIXELS/2-1 - pre_si; j < NUMPIXELS/2 -1 -si; j++){
        
        fill_solid(leds + j, 1, CHSV(j * delta, 255, 0));
        fill_solid(leds + NUMPIXELS-1 - j, 1, CHSV(j * delta, 255, 0));
      }
      FastLED.show();
      delay(20);
#endif      
      pre_si = si; 
      last_drop_time = millis();
    }   
  //delay(5);       
}

/*
音效描述：
1）HUE 色，两端向中心渐变聚拢
*/

void music_gathered(){
  
  { 
    //Serial.println(sig);
    int si = map(dot, 0, NUMPIXELS -1, 0, NUMPIXELS/2-1);//15
    Serial.printf("si %d\n", si); 
    if(si > pre_si){//音量更大
      int m = si;
      for(int j = 0; j <= si; j++){        
          fill_solid(leds + j, 1, CHSV((g_color+j * color_delta), 255, maxBrightness));
          fill_solid(leds + NUMPIXELS-1 - j, 1, CHSV((g_color+j * color_delta), 255, maxBrightness));
        FastLED.show();          
        delay(5);
      }

      pre_si = si;  
      last_drop_time = millis();
    }else{//音量变小
#if 1      
      for(int j = pre_si; j >= 0; j--){
        
        fill_solid(leds + j, 1, CHSV(j * color_delta, 255, 0));
        fill_solid(leds + NUMPIXELS-1 - j, 1, CHSV(j * color_delta, 255, 0));
        FastLED.show();
        delay(5);
      }
#endif      
      pre_si = si; 
      last_drop_time = millis();
    }   
  }

  //delay(5);       
}


/*
音效描述：
1）HUE 色，两端向中心渐变聚拢
*/

void music_gathered_fade(){
  

  //if (sig >= g_trigger_level)
  { 
    //Serial.println(sig);
    int si = map(dot, 0, NUMPIXELS -1, 0, NUMPIXELS/2-1);//15
    Serial.printf("si %d\n", si); 
    if(si > pre_si){//音量更大
      int m = si;
      for(int j = 0; j <= si; j++){        
          fill_solid(leds + j, 1, CHSV((g_color+j * color_delta), 255, (NUMPIXELS - j)* brightness_delta));
          fill_solid(leds + NUMPIXELS-1 - j, 1, CHSV((g_color+j * color_delta), 255, (NUMPIXELS - j) * brightness_delta));
        FastLED.show();          
        delay(5);
      }

      pre_si = si;  
      last_drop_time = millis();
    }else{//音量变小
#if 1      
      for(int j = pre_si; j >= 0; j--){
        
        fill_solid(leds + j, 1, CHSV(0, 255, 0));
        fill_solid(leds + NUMPIXELS-1 - j, 1, CHSV(0, 255, 0));
        FastLED.show();
        delay(5);
      }
#endif      
      pre_si = si; 
      last_drop_time = millis();
    }   
  }
    
}


int last_brightness = 0;
int last_color = 0;

/*
音效描述：
1）HUE 色，变色+亮度渐变
*/
void music_fade(){
        
  int sig = analogRead(MIC_PIN);//out引脚

  int delta = int(g_color / NUMPIXELS);
  //int delta = int(120 / NUMPIXELS);
  //int delta = random(0,250)/NUMPIXELS;//随机下颜色
  if (sig > sig_max)
  {
    sig = sig_max;// 防止超范围
  }

  if (sig >= g_trigger_level)
  { 
    //Serial.println(sig);
    int si = map(sig, g_trigger_level, sig_max, 0, NUMPIXELS-1);
    if(si > pre_si){//音量更大
      int j = 0;
      for(j = pre_si; j <= si; j++){
          fill_solid(leds, NUMPIXELS, CHSV((g_color+j * color_delta)%255, 255, j*brightness_delta));
          FastLED.show();
          delay(5);
      }  
      last_brightness = (j-1)*brightness_delta;
      last_color = (j-1) * delta;
      pre_si = si;
    }else{//音量变小
      int j = 0;
      for(j = pre_si; j >= si && j > 0; j--){
        fill_solid(leds, NUMPIXELS, CHSV(j * delta, 255, j*brightness_delta));
        FastLED.show();
        delay(5);
      }
      last_color = (j-1) * delta;
      last_brightness = (j-1)*brightness_delta;
      pre_si = si; 
    }
  }
  
  {//一直fade
      //for(int i = 0;drop_dot >= si; i ++)
      unsigned long interval = map(pre_si - si, 0, 31, 800, 5);//取5-100ms的掉落速度，两次音量落差越大，降速越快
      //Serial.printf("last_color %ld,%ld\n",last_color,drop_time); 
      if(millis() - drop_time > 200)//掉落间隔
      {
        if(last_brightness>0)
        {
          fill_solid(leds, NUMPIXELS, CHSV(last_color, 255, last_brightness-=brightness_delta));
          FastLED.show();
        }
        
        drop_time = millis();
      }
  }
  delay(5);          
}

/*
音效描述：
1）HUE 色，单色+亮度渐变
*/
void music_fade_single_color(){
        
  int sig = analogRead(MIC_PIN);//out引脚

  //int delta = int(g_color / NUMPIXELS);
  //int delta = int(120 / NUMPIXELS);
  //int delta = random(0,250)/NUMPIXELS;//随机下颜色
  if (sig > sig_max)
  {
    sig = sig_max;// 防止超范围
  }

  if (sig >= g_trigger_level)
  { 
    //Serial.println(sig);
    int si = map(sig, g_trigger_level, sig_max, 0, NUMPIXELS-1);
    if(si > pre_si){//音量更大
      int j = 0;
      for(j = 0; j <= si; j++){
          fill_solid(leds, NUMPIXELS, CHSV(g_color, 255, j*brightness_delta));
          FastLED.show();
          delay(5);
      }  
      last_brightness = (j-1)*brightness_delta;
      //last_color = (j-1) * delta;
      pre_si = si;
    }else{//音量变小
      int j = 0;
      for(j = pre_si; j >= si && j > 0; j--){
        fill_solid(leds, NUMPIXELS, CHSV(g_color, 255, j*brightness_delta));
        FastLED.show();
        delay(5);
      }
      //last_color = (j-1) * delta;
      last_brightness = (j-1)*brightness_delta;
      pre_si = si; 
      drop_time = millis();
    }
  }
  
  {//一直fade
      //for(int i = 0;drop_dot >= si; i ++)
      unsigned long interval = map(pre_si - si, 0, 31, 800, 5);//取5-100ms的掉落速度，两次音量落差越大，降速越快
      //Serial.printf("last_color %ld,%ld\n",last_color,drop_time); 
      if(millis() - drop_time > 10)//掉落间隔
      {
        if(last_brightness>0)
        {
          fill_solid(leds, NUMPIXELS, CHSV(g_color, 255, last_brightness--));
          FastLED.show();
        }
        
        drop_time = millis();
      }
  }
  delay(5);          
}

int shift_value = 1;

/*
音效描述：
1）HUE 色，音量越大，产生越多的亮点，滚动效果
*/
void music_follow(){
  int i = 0;
  
  int new_dot_count = 1;
  new_dot_count = map(dot, 0,NUMPIXELS-1, 0, 8);
  Serial.printf("new_dot_count %d\r\n",new_dot_count); 
  for(i = 0; i < new_dot_count; i++){
    shift_value <<= 1;
    shift_value |= 1; 
    Serial.printf("shift %x\r\n", shift_value);
  }

  if(dot>pre_dot){
    if(new_dot_count)
      for(int j = 0; j<NUMPIXELS;j++){
          for(i =0; i<NUMPIXELS;i++){
             int tmp = (shift_value >> i);
             
             if(tmp & 0x00000001)//判断每个灯位 是否亮灯
                leds[i] = CHSV(g_color, 255, maxBrightness);
             else
                leds[i] = CHSV(0, 0, 0);
             
          }
          shift_value <<= 1;
          FastLED.show();
          delay(10);
      }   
  }

}

/*
音效描述：
1）HUE 色，上推+掉落效果
*/
void music_up_down(){
        
  int sig = analogRead(MIC_PIN);//out引脚
  
  int delta = int(g_color / NUMPIXELS);
  //int delta = int(120 / NUMPIXELS);
  //int delta = random(0,250)/NUMPIXELS;//随机下颜色
  if (sig > sig_max)
  {
    sig_max = sig;
  }

  if (sig >= g_trigger_level)
  { 
    //Serial.println(sig);
    int si = map(sig, g_trigger_level, sig_max, 0, NUMPIXELS);
    if(si > pre_si){//音量更大
      for(int j = 0; j < si; j++){
          //pixels.setPixelColor(j, pixels.Color(128, 128, 0));
          //pixels.show();
          //fill_solid(leds + j, 1, CHSV((NUMPIXELS-j) * delta, 255, maxBrightness));
          //fill_solid(leds + j, 1, CHSV(j * delta, 255, maxBrightness));
          Serial.printf("j %d", j); 
          fill_solid(leds + j, 1, CHSV((g_color+j * color_delta)%255, 255, (NUMPIXELS-j) * brightness_delta));          
          FastLED.show();          
          delay(1);
      }
           
      pre_si = si;  
    }else{//音量变小
      for(int j = pre_si; j >= si; j--){
        //pixels.setPixelColor(j, pixels.Color(0, 0, 0));
        //pixels.show();
        fill_solid(leds + j, 1, CHSV(j * delta, 255, 0));
        FastLED.show();
        delay(10);
      }
      pre_si = si; 
    }
  }
  delay(5);          
}
